/*
 * app_filetransport_api.c
 *
 *  Created on: 2023年8月24日
 *      Author: HXF
 */

#include "app_filetransport_api.h"
#include "device.h"
#include "app_log.h"
#include "app_broadcast_retry.h"
#include "mac_transmitter.h"
#include "mac_receiver.h"
#include "bsp_wdog.h"
#include "app_key_value.h"
#ifdef HUB_DEVICE
#include "app_hub_api.h"
#else
#if(FILE_FLASH_ENABLE)
#include "app_multislot.h"
#include "bsp_sha.h"
#endif
#endif
typedef enum{
  NO_PRODUCTION,
  PRODUCTION_READY,
  PRODUCTION_WORK,
  PRODUCTION_ABORT,
  PRODUCTION_FINISH,
}FILE_PRODUCTION_E;

static FILE_TRANSPORT_E transport_step = NO_TRANSPORT;
static FILE_PRODUCTION_E production_step = NO_PRODUCTION;

bool file_log_enable = false;

FILE_TRANSPORT_E get_file_transport_step(void)
{
  return transport_step;
}

static void do_transport_start_event(void)
{
  FILE_TRANSPORT_ROLE_E role;
  unsigned char file_type = 0;
  getThisParam(ENbyTransFileType, &file_type);
  role = my_transport_role(file_type);
  if(role == PRODUCTION_ROLE){
      creat_ota_tx_notify_event();
      transport_step = PRODUCTION_NOTIFY;
  }else if(role == CONSUMPTION_ROLE){
      rxAlwaysOnEnable(true);
      transport_step = CONSUMPTION_REQUEST;
  }
}

static void do_ota_production_notify_event(void)
{
#ifdef HUB_DEVICE
  update_ota_rfm_id_buf();//删除不支持OTA的rfm
  if(check_ota_need_abort()){
      creat_ota_finish_event();
  }else{
      production_qrfh_notify();
      production_broadcast_notify();
      transport_step = PRODUCTION_HANDSHAKE;
  }
#endif
}

static void do_ota_production_notify_abort_event(void)
{
#ifdef HUB_DEVICE
  creat_ota_abort_event();
  transport_step = PRODUCTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_production_notify_finish_event(void)
{
#ifdef HUB_DEVICE
  creat_ota_finish_event();
  transport_step = PRODUCTION_FINISH_TRANSPORT;
#endif
}

static void do_ota_production_handshake_waitfinish_event(void)
{
#ifdef HUB_DEVICE
  //握手完成清除bcast_busy标志
  unsigned char bcast_busy = 0;
  setThisParam(ENbyBcastBusy, (unsigned char *)&bcast_busy);
  ota_init_production();
  if(check_ota_start_custom()){
      production_step = PRODUCTION_READY;
      start_fix_time_to_tx_file_Timer();
      transport_step = PRODUCTION_TRANSPORT_FILE;
  }else{ //产生异常
      creat_ota_abort_event();
  }
#endif
}

static void do_ota_production_handshake_timeout_event(void)
{
#ifdef HUB_DEVICE
  //握手超时，广播重传次数到的时候已经清除了bcast_busy标志
  update_ota_rfm_id_buf();//删除没有完成握手的rfm
  if(check_ota_need_abort()){
      creat_ota_finish_event();
  }else{
      ota_init_production();
      if(check_ota_start_custom()){
          production_step = PRODUCTION_READY;
          start_fix_time_to_tx_file_Timer();
          transport_step = PRODUCTION_TRANSPORT_FILE;
      }else{ //产生异常
          creat_ota_abort_event();
      }
  }
#endif
}

static void do_ota_production_handshake_abort_event(void)
{
#ifdef HUB_DEVICE
  //握手时出现异常清除bcast_busy标志
  unsigned char bcast_busy = 0;
  setThisParam(ENbyBcastBusy, (unsigned char *)&bcast_busy);
  creat_ota_abort_event();
  transport_step = PRODUCTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_production_handshake_finish_event(void)
{
#ifdef HUB_DEVICE
  //握手时结束OTA清除bcast_busy标志
  unsigned char bcast_busy = 0;
  setThisParam(ENbyBcastBusy, (unsigned char *)&bcast_busy);
  creat_ota_finish_event();
  transport_step = PRODUCTION_FINISH_TRANSPORT;
#endif
}

static void do_ota_production_file_txcheck_event(void)
{
#ifdef HUB_DEVICE
  transport_step = PRODUCTION_TRANSPORT_CHECK;
#endif
}

static void do_ota_production_file_abort_event(void)
{
#ifdef HUB_DEVICE
  creat_ota_abort_event();
  transport_step = PRODUCTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_production_check_waitfinish_event(void)
{
#ifdef HUB_DEVICE
  update_ota_rfm_id_buf();  //删除没有收到校验结果的rfm，或错误达到上限的rfm
  if(check_ota_need_abort()){
      creat_ota_finish_event();
      if(production_step == PRODUCTION_READY || production_step == PRODUCTION_WORK){
          production_step = PRODUCTION_ABORT;
      }
      return;
  }
  if(check_ota_rfm_all_finish()){
      creat_ota_finish_event();
      return;
  }
  update_history_file_link();
  if(check_ota_start_custom()){
      transport_step = PRODUCTION_TRANSPORT_FILE;
  }else{ //产生异常
      creat_ota_abort_event();
  }
#endif
}

static void do_ota_production_check_timeout_event(void)
{
#ifdef HUB_DEVICE
  update_ota_rfm_id_buf(); //删除没有收到校验结果的rfm，或错误达到上限的rfm
  if(check_ota_need_abort()){
      creat_ota_finish_event();
      if(production_step == PRODUCTION_READY || production_step == PRODUCTION_WORK){
          production_step = PRODUCTION_ABORT;
      }
      return;
  }
  if(check_ota_rfm_all_finish()){
      creat_ota_finish_event();
      return;
  }
  update_history_file_link();
  if(check_ota_start_custom()){
      transport_step = PRODUCTION_TRANSPORT_FILE;
  }else{ //产生异常
      creat_ota_abort_event();
  }
#endif
}

static void do_ota_production_check_abort_event(void)
{
#ifdef HUB_DEVICE
  creat_ota_abort_event();
  transport_step = PRODUCTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_production_check_finish_event(void)
{
#ifdef HUB_DEVICE
  creat_ota_finish_event();
  transport_step = PRODUCTION_FINISH_TRANSPORT;
#endif
}

static void do_ota_production_abort_transport(void)
{
#ifdef HUB_DEVICE
//强制退出升级 比如panel强制退出，一些异常情况
  if(production_step == PRODUCTION_READY || production_step == PRODUCTION_WORK){
      production_step = PRODUCTION_ABORT;
  }
  update_all_ota_rfm_finish_state(OTA_ERR_ABORT);
  stop_fix_time_to_tx_file_Timer();
  ota_abort_hook();
  transport_step = NO_TRANSPORT;
#endif
}

static void do_ota_production_finish_transport(void)
{
#ifdef HUB_DEVICE
  //OTA结束，成功或失败
  if(production_step == PRODUCTION_READY || production_step == PRODUCTION_WORK){
      production_step = PRODUCTION_ABORT;
  }
  stop_fix_time_to_tx_file_Timer();
  ota_abort_hook();
  transport_step = NO_TRANSPORT;
#endif
}

static void do_ota_custom_wait_consult_timeout(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_wait_consult_finish(void)
{
#ifdef RFM_DEVICE
  transport_step = CONSUMPTION_CONFIRM;
#endif
}

static void do_ota_custom_wait_consult_abort(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_confirm_finish(void)
{
#ifdef RFM_DEVICE
  ota_init_custom();
  transport_step = CONSUMPTION_RECEVE;
#endif
}

static void do_ota_custom_confirm_timeout(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_confirm_abort(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_wait_file_timeout(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_rcv_file(void)
{
#ifdef RFM_DEVICE
  cache_page_file_t page_msg = {0};
  int page_msg_len = 0;
  unsigned char valid_file[448] = {0}; //224*2
  int valid_file_len = 0;
  unsigned char valid_pageid[2] = {0};
  bool bret = false;
#if(FILE_FLASH_ENABLE)
  uint32_t ota_offset = 0;
#endif
  if(file_cache_link_pop(FILE_LINK_1, (unsigned char *)&page_msg, &page_msg_len) == 0){
      if(file_log_enable){
          APP_PRINTF("bid %d, pid %d\r\n",page_msg.block_id, ((page_msg.page_id[0] << 8)+page_msg.page_id[1]));
      }
      if(!check_file_crc32_is_sample(page_msg.data, page_msg.data_len,
                                     (unsigned char *)&page_msg.data[page_msg.data_len + 0], 4)){
          if(file_log_enable){
              APP_PRINTF("crc error\r\n");
          }
          return;
      }
      if(chcek_file_is_exist_by_pageid(page_msg.page_id)){
          if(file_log_enable){
              APP_PRINTF("is_exist error\r\n");
          }
          return;
      }

      bret = deal_file_payload(page_msg.page_id, page_msg.data, page_msg.data_len,
                               valid_pageid, valid_file, &valid_file_len);
      if(bret){
#if(FILE_FLASH_ENABLE)
          watchDogFeed();
          ota_offset = (((valid_pageid[0] << 8)+valid_pageid[1]) - 1) * 224;
          write_data_to_slot(ota_offset, valid_file, valid_file_len);
#endif
      }
  }
#endif
}

static void do_ota_custom_rcv_check(void)
{
#ifdef RFM_DEVICE
  unsigned char updateme_id_num = 0;
  keyValue_t kv = {0};
  char msg[2] = {0};
  unsigned char flag = 0;
#if(FILE_FLASH_ENABLE)
  unsigned char slot_file[224] = {0};
  unsigned char file_size[4] = {0x00};
  int size = 0;
  int offset = 0;
  unsigned char read_size = 0;
  unsigned char verify_mode = FILE_VERIFY_UNKNOWN;
  psa_hash_operation_t verify_op;
  unsigned char *ptr_verify_code = NULL;
#endif
  if(check_custom_receve_file_finish()){
#if(FILE_FLASH_ENABLE)
      watchDogFeed();
      DS_app_func_tm_in();
      //flag = (verify_application() == BOOTLOADER_OK)?1:2; //flag 0,没结束；1，校验成功，2校验失败
      //TODO 读ram;
      //TODO 计算sha256
      verify_mode = get_custom_file_verify_mode();
      if(verify_mode == FILE_VERIFY_UNKNOWN){
          flag = 2;
      }else{
          DS_hash_stream_operation_init(&verify_op,HASH_SHA2_256);
          get_file_file_size(file_size);
          size = (file_size[0] << 24) + (file_size[1] << 16) + (file_size[2] << 8) + (file_size[3]);
          if(size > 44){
              size -= 44;
          }else{
              size = 0;
          }
          while(size){
              read_size = (size >= 224)?224:size;
              read_data_from_slot(offset, (uint8_t *)slot_file, read_size);
              DS_hash_stream_update(&verify_op, (uint8_t *)slot_file, read_size);//分块

              size -= read_size;
              offset += read_size;
          }
          ptr_verify_code = get_custom_file_verify_code();
          if(!ptr_verify_code){
              flag = 2;
          }else{
              flag = (DS_hash_stream_verify(&verify_op, ptr_verify_code, 32) == DS_SHA_STATUS_SUCCESS) ? 1 : 2;
          }
      }
      DS_app_func_tm_end("verify");

#else
      flag = 1;
#endif
      set_custom_file_finish_flag(flag);
      if(flag == 1){
          creat_ota_finish_event();
      }else if(flag == 2){
          creat_ota_abort_event();
      }
  }
  getThisParam(ENbyOtaUpdatemeIDNum, &updateme_id_num);
  if(updateme_id_num == 1){
      kv.id = 0xfb;
      packet_check_response(kv.value, &kv.valueSize);
      if(kv.valueSize){
          set_key_value(&kv);
      }
  }else{
      msg[0] = 1;
      msg[1] = 0xf1;
      start_timer_to_trigger_updateme_response(msg, 2, NULL);
  }
#endif
}

static void do_ota_custom_rcv_abort(void)
{
#ifdef RFM_DEVICE
  creat_ota_abort_event();
  transport_step = CONSUMPTION_ABORT_TRANSPORT;
#endif
}

static void do_ota_custom_rcv_finish(void)
{
#ifdef RFM_DEVICE
  creat_ota_finish_event();
  transport_step = CONSUMPTION_FINISH_TRANSPORT;
#endif
}

static void do_ota_custom_abort_transport(void)
{
#ifdef RFM_DEVICE
#if(FILE_FLASH_ENABLE)
  if(file_log_enable){
      APP_PRINTF("erase slot\r\n");
  }
  watchDogFeed();
  erase_slot_if_needed();
#endif
  ota_abort_hook();
  rxAlwaysOnEnable(false);
  transport_step = NO_TRANSPORT;
#endif
}

static void do_ota_custom_finish_transport(void)
{
#ifdef RFM_DEVICE
  //成功重启
#if(FILE_FLASH_ENABLE)
  if(file_log_enable){
      APP_PRINTF("delay reboot\r\n");
  }
  start_timer_to_delay_app_install_and_reboot();
  //不需要ota_abort_hook rxAlwaysOnEnable(false); transport_step = NO_TRANSPORT; 因为会重启
#else
  ota_abort_hook();
  rxAlwaysOnEnable(false);
  transport_step = NO_TRANSPORT;
#endif
#endif
}

static void do_ota_custom_finish_transport_check_evt(void)
{
#if(FILE_FLASH_ENABLE)
  unsigned char updateme_id_num = 0;
  keyValue_t kv = {0};
  char msg[2] = {0};
  getThisParam(ENbyOtaUpdatemeIDNum, &updateme_id_num);
  if(updateme_id_num == 1){
      kv.id = 0xfb;
      packet_check_response(kv.value, &kv.valueSize);
      if(kv.valueSize){
          set_key_value(&kv);
      }
  }else{
      msg[0] = 1;
      msg[1] = 0xf1;
      start_timer_to_trigger_updateme_response(msg, 2, NULL);
  }
  start_timer_to_delay_app_install_and_reboot();
#endif
}

void file_transport_task(void)
{
  if(file_evt_link_is_empty()){
      return;
  }
  FILE_EVENT_E evt;
  unsigned char file_type = 0;
  getThisParam(ENbyTransFileType, &file_type);
  file_evt_link_pop(&evt);
  if(file_log_enable){
      APP_PRINTF("file %d -%d\n",transport_step,evt);
  }

  switch(transport_step){
    case NO_TRANSPORT:
      if(evt == FILE_EVENT_START){
          do_transport_start_event();  //分配角色
      }
      break;
    case PRODUCTION_NOTIFY:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_TX_NOTIFY){
              do_ota_production_notify_event();
          }else if(evt == FILE_EVENT_ABORT){
              do_ota_production_notify_abort_event();
          }else if(evt == FILE_EVENT_FINISH){
              do_ota_production_notify_finish_event();
          }
      }else{
          //TODO
      }
      break;
    case PRODUCTION_HANDSHAKE:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_WAIT_FINISH){
              do_ota_production_handshake_waitfinish_event();
          }else if(evt == FILE_EVENT_WAIT_TIMEOUT){
              do_ota_production_handshake_timeout_event();
          }else if(evt == FILE_EVENT_ABORT){
              do_ota_production_handshake_abort_event();
          }else if(evt == FILE_EVENT_FINISH){
              do_ota_production_handshake_finish_event();
          }
      }else{
          //TODO
      }
      break;
    case PRODUCTION_TRANSPORT_FILE:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_TX_CHECK){
              do_ota_production_file_txcheck_event();
          }else if(evt == FILE_EVENT_ABORT){
              do_ota_production_file_abort_event();
          }
      }else{
          //TODO
      }
      break;
    case PRODUCTION_TRANSPORT_CHECK:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_WAIT_FINISH){
              do_ota_production_check_waitfinish_event();
          }else if(evt == FILE_EVENT_WAIT_TIMEOUT){
              do_ota_production_check_timeout_event();
          }else if(evt == FILE_EVENT_ABORT){
              do_ota_production_check_abort_event();
          }else if(evt == FILE_EVENT_FINISH){
              do_ota_production_check_finish_event();
          }
      }
      break;
    case PRODUCTION_ABORT_TRANSPORT:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_ABORT){
              do_ota_production_abort_transport();
          }
      }else{
          //TODO
      }
      break;
    case PRODUCTION_FINISH_TRANSPORT:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_FINISH){
              do_ota_production_finish_transport();
          }
      }else{
          //TODO
      }
      break;

    case CONSUMPTION_REQUEST:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_WAIT_TIMEOUT){
              do_ota_custom_wait_consult_timeout();  //超时没有收到hub的信息，退出OTA
          }else if(evt == FILE_EVENT_WAIT_FINISH){
              do_ota_custom_wait_consult_finish();  //收到了协商报文，准备发确认报文
          }else if(evt == FILE_EVENT_ABORT){         //出现了异常，退出OTA
              do_ota_custom_wait_consult_abort();
          }else if(evt == FILE_EVENT_START){  //由于hub没有收到请求物模型，rfm会在这个阶段重新收到重传的固件升级广播

          }
      }else{
          //TODO
      }
      break;
    case CONSUMPTION_CONFIRM:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_WAIT_FINISH){
              do_ota_custom_confirm_finish();
          }else if(evt == FILE_EVENT_WAIT_TIMEOUT){
              do_ota_custom_confirm_timeout();
          }else if(evt == FILE_EVENT_ABORT){
              do_ota_custom_confirm_abort();
          }
      }else{
          //TODO
      }
      break;
    case CONSUMPTION_RECEVE:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_WAIT_TIMEOUT){ //没有收到文件
              do_ota_custom_wait_file_timeout();
          }else if(evt == FILE_EVENT_RCV_FILE){ //收到文件
              do_ota_custom_rcv_file();
          }else if(evt == FILE_EVENT_RCV_CHECK){ //收到校验请求
              do_ota_custom_rcv_check();
          }else if(evt == FILE_EVENT_ABORT){  //异常中断
              do_ota_custom_rcv_abort();
          }else if(evt == FILE_EVENT_FINISH){
              do_ota_custom_rcv_finish();
          }
      }else{
          //TODO
      }
      break;
    case CONSUMPTION_ABORT_TRANSPORT:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_ABORT){
              do_ota_custom_abort_transport();
          }
      }else{
          //TODO
      }
      break;
    case CONSUMPTION_FINISH_TRANSPORT:
      if(file_type == FTYPE_OTA){
          if(evt == FILE_EVENT_FINISH){
              do_ota_custom_finish_transport();
          }else if(evt == FILE_EVENT_RCV_CHECK){
              do_ota_custom_finish_transport_check_evt();
          }
      }else{
          //TODO
      }
      break;
    default:
      break;
  }
}

static void do_production_ready(void)
{
  unsigned char file_type = 0;
#ifdef HUB_DEVICE
  unsigned char blockid = 0;
  unsigned char idx = 0;
#endif
  getThisParam(ENbyTransFileType, &file_type);
  if(my_transport_role(file_type) != PRODUCTION_ROLE){
      production_step = NO_PRODUCTION;
      return;
  }
  if(file_type == FTYPE_OTA){
#ifdef HUB_DEVICE
      if(check_ota_start_production()){
          blockid = get_ota_production_blockid();
          DS_hub_api_creat_file_event(NEED_FILE_TRANSPORT, &blockid, 1);
          production_step = PRODUCTION_WORK;
          getThisParam(ENbyWriteFileLinkIdx, &idx);
          if(file_log_enable){
              APP_PRINTF("production to work bid:%d, cache[%d]\r\n",blockid,idx);
          }
      }
#endif
  }else{

  }
}

static void do_production_work(void)
{
  unsigned char file_type = 0;
  getThisParam(ENbyTransFileType, &file_type);
  if(my_transport_role(file_type) != PRODUCTION_ROLE){
      production_step = NO_PRODUCTION;
      return;
  }
  if(file_type == FTYPE_OTA){
#ifdef HUB_DEVICE
      if(check_ota_production_no_run()){ //产生异常
          production_step = PRODUCTION_ABORT;
          update_all_ota_rfm_finish_state(OTA_ERR_NO_FILE);
          creat_ota_abort_event();
          if(file_log_enable){
              APP_PRINTF("production to abort\r\n");
          }
          return;
      }
      if(check_ota_finish_production()){
          production_step = PRODUCTION_FINISH;
          if(file_log_enable){
              APP_PRINTF("production to finish\r\n");
          }
          return;
      }
      if(check_ota_suspend_production()){
          production_step = PRODUCTION_READY;
          if(file_log_enable){
              APP_PRINTF("production to ready\r\n");
          }
          return;
      }
#endif
  }else{

  }
}

static void do_production_abort(void)
{
  production_step = NO_PRODUCTION;
}

static void do_production_finish(void)
{
  production_step = NO_PRODUCTION;
}

void file_production_task(void)
{
  switch(production_step){
    case NO_PRODUCTION:
      break;
    case PRODUCTION_READY:
      do_production_ready();
      break;
    case PRODUCTION_WORK:
      do_production_work();
      break;
    case PRODUCTION_ABORT:
      do_production_abort();
      break;
    case PRODUCTION_FINISH:
      do_production_finish();
      break;
    default:
      break;
  }
}

void DS_file_api_init(void)
{
  get_api_log_enable(FILE_API_LOG, &file_log_enable);
  file_link_init();
}

void DS_file_api_task(void)
{
  file_transport_task();
  file_production_task();
}

